{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "import numpy as np\n",
    "from tensorflow.keras.layers import Dense, Flatten, Conv2D\n",
    "from tensorflow.keras import Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "mnist = tf.keras.datasets.mnist\n",
    "#tune float\n",
    "(x_train, y_train), (x_test, y_test) = mnist.load_data()\n",
    "x_train, x_test = x_train / 255.0, x_test / 255.0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "keras方式训练模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = tf.keras.models.Sequential([\n",
    "  tf.keras.layers.Flatten(input_shape=(28, 28)),\n",
    "  tf.keras.layers.Dense(128, activation='relu'),\n",
    "  tf.keras.layers.Dropout(0.2),\n",
    "  tf.keras.layers.Dense(10, activation='softmax')\n",
    "])\n",
    "\n",
    "model.compile(optimizer='adam',\n",
    "              loss='sparse_categorical_crossentropy',\n",
    "              metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 60000 samples\n",
      "Epoch 1/5\n",
      "60000/60000 [==============================] - 5s 91us/sample - loss: 0.2969 - accuracy: 0.9144\n",
      "Epoch 2/5\n",
      "60000/60000 [==============================] - 5s 86us/sample - loss: 0.1446 - accuracy: 0.9568\n",
      "Epoch 3/5\n",
      "60000/60000 [==============================] - 5s 88us/sample - loss: 0.1075 - accuracy: 0.9679\n",
      "Epoch 4/5\n",
      "60000/60000 [==============================] - 5s 84us/sample - loss: 0.0877 - accuracy: 0.9735\n",
      "Epoch 5/5\n",
      "60000/60000 [==============================] - 5s 85us/sample - loss: 0.0742 - accuracy: 0.9772\n",
      "10000/10000 - 1s - loss: 0.0799 - accuracy: 0.9757\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[0.0799021470952779, 0.9757]"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.fit(x_train, y_train, epochs=5)\n",
    "\n",
    "model.evaluate(x_test,  y_test, verbose=2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tensorflow2.x训练方式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Add a channels dimension\n",
    "x_train = x_train[..., tf.newaxis]\n",
    "x_test = x_test[..., tf.newaxis]\n",
    "\n",
    "#tf.data\n",
    "train_ds = tf.data.Dataset.from_tensor_slices((x_train, y_train)).shuffle(10000).batch(32)\n",
    "test_ds = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(32)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MyModel(Model):\n",
    "    #define model type\n",
    "    def __init__(self):\n",
    "        super(MyModel, self).__init__()\n",
    "        #Sequential\n",
    "        self.conv1 = Conv2D(32, 3, activation='relu')\n",
    "        self.flatten = Flatten()\n",
    "        self.d1 = Dense(128, activation='relu')\n",
    "        self.d2 = Dense(10, activation='softmax')\n",
    "    \n",
    "    #inputs\n",
    "    def call(self, x):\n",
    "        x = self.conv1(x)\n",
    "        x = self.flatten(x)\n",
    "        x = self.d1(x)\n",
    "        return self.d2(x)\n",
    "\n",
    "model = MyModel()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "loss_object = tf.keras.losses.SparseCategoricalCrossentropy()\n",
    "\n",
    "optimizer = tf.keras.optimizers.Adam()\n",
    "\n",
    "train_loss = tf.keras.metrics.Mean(name='train_loss')\n",
    "train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')\n",
    "\n",
    "test_loss = tf.keras.metrics.Mean(name='test_loss')\n",
    "test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='test_accuracy')\n",
    "\n",
    "@tf.function                             #acceleration training \n",
    "def train_step(images, labels):\n",
    "    with tf.GradientTape() as tape:                     #calculate Gradient connect def and var\n",
    "        predictions = model(images)                     #Tensor(\"my_model/dense_3/Softmax:0\")\n",
    "        loss = loss_object(labels, predictions)\n",
    "    gradients = tape.gradient(loss, model.trainable_variables)\n",
    "    \n",
    "    optimizer.apply_gradients(zip(gradients, model.trainable_variables))\n",
    "\n",
    "    train_loss(loss)                      #trans type\n",
    "    train_accuracy(labels, predictions)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "#测试模型\n",
    "@tf.function\n",
    "def test_step(images, labels):\n",
    "    predictions = model(images)\n",
    "    t_loss = loss_object(labels, predictions)\n",
    "\n",
    "    test_loss(t_loss)                     #trans type\n",
    "    test_accuracy(labels, predictions)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:Layer my_model_1 is casting an input tensor from dtype float64 to the layer's dtype of float32, which is new behavior in TensorFlow 2.  The layer has dtype float32 because it's dtype defaults to floatx.\n",
      "\n",
      "If you intended to run this layer in float32, you can safely ignore this warning. If in doubt, this warning is likely only an issue if you are porting a TensorFlow 1.X model to TensorFlow 2.\n",
      "\n",
      "To change all layers to have dtype float64 by default, call `tf.keras.backend.set_floatx('float64')`. To change just this layer, pass dtype='float64' to the layer constructor. If you are the author of this layer, you can disable autocasting by passing autocast=False to the base Layer constructor.\n",
      "\n",
      "Epoch 1, Loss: 0.13099157810211182, Accuracy: 96.06666564941406, Test Loss: 0.06699678301811218, Test Accuracy: 97.79999542236328\n",
      "Epoch 2, Loss: 0.04127798601984978, Accuracy: 98.7316665649414, Test Loss: 0.05322837084531784, Test Accuracy: 98.25\n",
      "Epoch 3, Loss: 0.020942630246281624, Accuracy: 99.32833099365234, Test Loss: 0.05569441616535187, Test Accuracy: 98.4000015258789\n",
      "Epoch 4, Loss: 0.012188010849058628, Accuracy: 99.58666229248047, Test Loss: 0.05575696378946304, Test Accuracy: 98.33999633789062\n",
      "Epoch 5, Loss: 0.009336365386843681, Accuracy: 99.69666290283203, Test Loss: 0.06403914839029312, Test Accuracy: 98.43999481201172\n"
     ]
    }
   ],
   "source": [
    "#训练模型\n",
    "N_EPOCHS = 5\n",
    "for epoch in range(1,N_EPOCHS+1):\n",
    "    # 在下一个epoch开始时，重置评估指标,no necessary\n",
    "    train_loss.reset_states()\n",
    "    train_accuracy.reset_states()\n",
    "    test_loss.reset_states()\n",
    "    test_accuracy.reset_states()\n",
    "\n",
    "    for images, labels in train_ds:\n",
    "        train_step(images, labels)\n",
    "\n",
    "    for test_images, test_labels in test_ds:\n",
    "        test_step(test_images, test_labels)\n",
    "\n",
    "    template = 'Epoch {}, Loss: {}, Accuracy: {}, Test Loss: {}, Test Accuracy: {}'\n",
    "    print (template.format(epoch,\n",
    "                           train_loss.result(),                              #tensor tune float\n",
    "                           train_accuracy.result()*100,\n",
    "                           test_loss.result(),\n",
    "                           test_accuracy.result()*100))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
